package cn.hyatt.auth.service.impl;

import cn.hyatt.auth.dto.systemUser.SystemUserFindDto;
import cn.hyatt.auth.dto.systemUser.SystemUserSaveDto;
import cn.hyatt.auth.dto.systemUser.SystemUserUpdateDto;
import cn.hyatt.auth.dto.systemUser.SystemUserVo;
import cn.hyatt.auth.entity.SystemUser;
import cn.hyatt.auth.entity.SystemUserRole;
import cn.hyatt.auth.event.SystemUserEvent;
import cn.hyatt.auth.mapper.SystemUserMapper;
import cn.hyatt.auth.service.SystemUserRoleService;
import cn.hyatt.auth.service.SystemUserService;
import cn.hyatt.common.exception.BusinessException;
import cn.hyatt.common.utils.ValidationUtil;
import cn.hyatt.core.utils.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.List;
import java.util.Optional;

/**
 * 系统用户-服务实现
 *
 * @author hyatt
 */
@Slf4j
@Service
@Primary
@AllArgsConstructor
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {

    private final String KEY = "system:user:";
    private RedissonClient redissonClient;

    private ApplicationEventPublisher publisher;
    private SystemUserRoleService systemUserRoleService;

    @Override
    public List<SystemUser> findByList(SystemUserFindDto dto) {
        return baseMapper.findByList(dto);
    }

    @Override
    public IPage<SystemUser> findByPage(SystemUserFindDto dto) {
        return baseMapper.findByPage(PageUtil.page(dto), dto);
    }

    @Override
    public Optional<SystemUser> findByUsername(String username) {
        SystemUser systemUser = baseMapper.selectOne(new LambdaQueryWrapper<SystemUser>()
                .eq(SystemUser::getUsername, username));
        return Optional.ofNullable(systemUser);
    }

    @Override
    public Optional<SystemUserVo> getCacheById(Long id) {
        RBucket<SystemUserVo> bucket = redissonClient.getBucket(KEY + id);
        if (bucket.isExists()) {
            return Optional.of(bucket.get());
        }
        Optional<SystemUser> opt = getOptById(id);
        Optional<SystemUserVo> voOptional = opt.map(this::toVo);
        voOptional.ifPresent(this::saveCache);
        return voOptional;
    }

    @Override
    public Optional<SystemUserVo> getCacheByUsername(String username) {
        RBucket<String> usernameBucket = redissonClient.getBucket(KEY + username);
        if (usernameBucket.isExists()) {
            RBucket<SystemUserVo> bucket = redissonClient.getBucket(usernameBucket.get());
            return Optional.of(bucket.get());
        }
        Optional<SystemUser> opt = findByUsername(username);
        Optional<SystemUserVo> voOptional = opt.map(this::toVo);
        voOptional.ifPresent(this::saveCache);
        return voOptional;
    }

    @Override
    public void saveCache(SystemUserVo vo) {
        // 保存 用户信息有效期60分钟
        RBucket<SystemUserVo> bucket = redissonClient.getBucket(KEY + vo.getId());
        bucket.set(vo, Duration.ofMinutes(60));
        RBucket<String> usernameBucket = redissonClient.getBucket(KEY + vo.getUsername());
        usernameBucket.set(KEY + vo.getId(), Duration.ofMinutes(60));
    }

    @Override
    @Transactional
    public void save(SystemUserSaveDto dto) {
        // Copy 属性
        SystemUser entity = new SystemUser();
        BeanUtils.copyProperties(dto, entity);
        // 验证数据内容
        ValidationUtil.validate(entity);
        // 插入数据
        baseMapper.insert(entity);

        // 发布事件
        publisher.publishEvent(new SystemUserEvent.Save(entity));
    }

    @Override
    @Transactional
    public void update(Long id, SystemUserUpdateDto dto) {
        // 获取修改对象
        Optional<SystemUser> optional = getOptById(id);
        SystemUser entity = optional.orElseThrow(
                () -> new BusinessException("找不到Id为(" + id + ")的数据")
        );
        // 保留旧实体记录
        SystemUser oldEntity = new SystemUser();
        BeanUtils.copyProperties(entity, oldEntity);
        // Copy 属性
        BeanUtils.copyProperties(dto, entity);
        // 验证数据内容
        ValidationUtil.validate(entity);
        // 按Id更新
        baseMapper.updateById(entity);

        // 发布事件
        publisher.publishEvent(new SystemUserEvent.Update(oldEntity, entity));
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        // 按Id删除
        baseMapper.deleteById(id);
        // 发布事件
        publisher.publishEvent(new SystemUserEvent.Delete(id));
    }

    @Override
    public void deleteCacheById(Long id) {
        RBucket<SystemUserVo> bucket = redissonClient.getBucket(KEY + id);
        bucket.delete();
    }

    @Override
    public SystemUserVo toVo(SystemUser entity) {
        // Copy 属性
        SystemUserVo vo = new SystemUserVo();
        BeanUtils.copyProperties(entity, vo);

        // 获取用户角色
        List<SystemUserRole> userRoleList = systemUserRoleService.list(new LambdaQueryWrapper<SystemUserRole>()
                .eq(SystemUserRole::getUserId, entity.getId()));
        List<Long> roleList = userRoleList.stream().map(SystemUserRole::getRoleId).toList();
        vo.setRoleList(roleList);
        return vo;
    }
}
